// axios#request(config)
// axios#get(url[, config])
// axios#delete(url[, config])
// axios#head(url[, config])
// axios#options(url[, config])
// axios#post(url[, data[, config]])
// axios#put(url[, data[, config]])
// axios#patch(url[, data[, config]])

let defaultConfig = {
  baseUrl: '',
  url: '',
  data: {},
  header: {},
  method: 'GET',
}

export class Http {
  constructor(config = {}) {
    this.config = mergeConfig(defaultConfig, config)
    this.reqTask = null
    this.interceptors = {
      request: new InterceptorManager(),
      response: new InterceptorManager(),
    }
  }

  request(config = {}) {
    config = mergeConfig(this.config, config)
    let chains = [
      (config) => {
        return new Promise((resolve, reject) => {
          this.reqTask = wx.request({
            url: config.baseUrl + config.url,
            data: config.data,
            header: config.header,
            method: config.method,
            success: (response) => resolve(response),
            fail: (reason) => reject(reason),
          })
        })
      },
      undefined,
    ]
    for (const handler of this.interceptors.request.handlers) {
      chains.unshift(handler.fulfilled, handler.rejected)
    }
    for (const handler of this.interceptors.response.handlers) {
      chains.push(handler.fulfilled, handler.rejected)
    }
    let promise = Promise.resolve(config)
    while (chains.length) {
      promise = promise.then(chains.shift(), chains.shift())
    }
    return promise
  }

  get(url, config = {}) {
    config['url'] = url
    config['method'] = 'GET'
    return this.request(config)
  }

  post(url, data, config = {}) {
    config['url'] = url
    config['method'] = 'POST'
    config['data'] = data
    return this.request(config)
  }

  abort() {
    if (this.reqTask) this.reqTask.abort()
  }
}

function mergeConfig(target, source = {}) {
  let cfg = {}
  for (const [key, value] of Object.entries(target)) {
    if (source.hasOwnProperty(key)) {
      if (value instanceof Object) {
        if (source[key] instanceof Object) {
          cfg[key] = Object.assign({}, target[key], source[key])
        }
      }
    }
  }
  return Object.assign({}, target, source, cfg)
}

class InterceptorManager {
  constructor() {
    this.handlers = []
  }

  use(fulfilled, rejected) {
    this.handlers.push({ fulfilled, rejected })
  }
}
